package org.example.bean;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.example.enums.Constant;
import org.example.enums.GridType;
import org.example.thread.ThreadPoolManager;
import org.example.thread.ThreadTask;
import org.example.util.ExceptionUtil;
import org.example.util.MapUtil;
import org.example.util.ThetaStarUtil;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @Desc:游戏地图信息
 * @Author: yanghongjun
 * @Date: 2024/5/6
 **/
@Data
public class GameMap {
    private static final Logger logger = LogManager.getLogger(GameMap.class);

    /**
     * 寻路8个方向
     */
    private final int[][] moves = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
    /**
     * 游戏坐标和寻路格子转换比例
     */
    private final float cordPosRatio;
    private final int cordPosRatioInt;
    /**
     * 地图尺寸（游戏坐标单位）
     */
    private final int mapWidth;
    private final int mapHeight;
    /**
     * 坐标格子二维数组
     */
    private Grid[][] grids;
    /**
     * 地图寻路格子长宽，精细到0.1（坐标*10）
     */
    private final int pointMaxX;
    private final int pointMaxY;
    /**
     * 阻挡哈希稀疏矩阵 用于寻路 精细到0.1（坐标*10）
     */
    private final Map<Integer, Set<Integer>> blocks;
    /**
     * 寻路节点对象池
     */
    private final ThreadLocalNodePool nodePool;
    /**
     * 疆域数据
     */
    private final HashMap<Integer, Territory> territoryMap;
    /**
     * 关卡数据
     */
    private final HashMap<Long, MapPass> mapPassMap;
    /**
     * 关卡通行路径缓存
     */
    private final HashMap<Integer, HashMap<Integer, List<JsonGamePos>>> passPathCacheMap;


    public ThreadLocalNodePool getNodePool() {
        return nodePool;
    }

    /**
     * 初始化地图数据
     *
     * @param mapWidth
     * @param mapHeight
     */
    public GameMap(int mapWidth, int mapHeight) {
        this.mapWidth = mapWidth;
        this.mapHeight = mapHeight;

        this.cordPosRatio = 10.0f;
        this.cordPosRatioInt = (int) cordPosRatio;

        this.pointMaxX = mapWidth * cordPosRatioInt;
        this.pointMaxY = mapHeight * cordPosRatioInt;

        this.blocks = new HashMap<>();
        this.nodePool = new ThreadLocalNodePool(Constant.TEN_THOUSAND, pointMaxX * pointMaxY);
        for (int i = 0; i < ThreadPoolManager.FIND_PATH_THREAD_NUM; i++) {
            ThreadPoolManager.getInstance().addFindPathTask(new ThreadTask("预热") {
                @Override
                protected void action() {
                    Node acquire = nodePool.acquire();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    nodePool.release(acquire);
                }
            });
        }
        this.territoryMap = new HashMap<>();
        this.mapPassMap = new HashMap<>();
        this.passPathCacheMap = new HashMap<>();
        logger.info("Creating a new GameMap with size: {}x{}", mapWidth, mapHeight);
        initializeGrids();
        setMapPassMap();
        setupTerritoriesAndPasses();
        logger.info("Loaded GameMap");
    }


    // =============================
    // 初始化方法
    // =============================

    /**
     * 初始化游戏坐标格子二维数组
     */
    private void initializeGrids() {
        grids = new Grid[mapWidth][mapHeight];
        for (int i = 0; i < mapWidth; i++) {
            for (int j = 0; j < mapHeight; j++) {
                int gridMinX = i * cordPosRatioInt;
                int gridMinY = j * cordPosRatioInt;
                int gridMaxX = (i + 1) * cordPosRatioInt;
                int gridMaxY = (j + 1) * cordPosRatioInt;
                grids[i][j] = new Grid(i, j, gridMinX, gridMaxX, gridMinY, gridMaxY);
            }
        }
    }

    // 从文件读取 List<PassCfg>
    public static List<PassCfg> load() {
        ObjectMapper mapper = new ObjectMapper();
        File file = new File("src/main/resources/passcfg_list.json");
        try {
            return mapper.readValue(file, mapper.getTypeFactory().constructCollectionType(List.class, PassCfg.class));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 设置关卡数据
     */
    private void setMapPassMap() {
        List<PassCfg> load = load();
        if (load != null) {
            for (PassCfg passCfg : load) {
                MapPass mapPass = new MapPass(passCfg);
                mapPassMap.put(mapPass.getId(), mapPass);
                //设置连接点所在格子类型和关卡id
                for (Cord cord : mapPass.getCordHashMap().values()) {
                    grids[cord.getX()][cord.getY()].setType(GridType.CONNECTION);
                    grids[cord.getX()][cord.getY()].setPassId(passCfg.ID);
                }
            }
        }
    }

    /**
     * 初始化疆域并建立关卡连接关系
     */
    private void setupTerritoriesAndPasses() {
        List<Integer> list = Arrays.asList(5, 6, 7, 8, 9, 10);
        for (Integer i : list) {
            territoryMap.put(i, new Territory(i));
        }
        for (MapPass mapPass : mapPassMap.values()) {
            //构建疆域之间的连接关系
            List<Integer> ids = new ArrayList<>(mapPass.getCordHashMap().keySet());
            Set<String> visitedPairs = new HashSet<>();
            for (int i = 0; i < ids.size(); i++) {
                Integer idA = ids.get(i);
                for (int j = i + 1; j < ids.size(); j++) {
                    Integer idB = ids.get(j);
                    String pairKey = Math.min(idA, idB) + "-" + Math.max(idA, idB);
                    if (!visitedPairs.contains(pairKey)) {
                        Territory a = territoryMap.get(idA);
                        Territory b = territoryMap.get(idB);
                        if (a != null && b != null) {
                            connectTerritories(a, b, mapPass);
                        } else {
                            logger.error("无效疆域连接: {} <-> {}", idA, idB);
                        }
                        visitedPairs.add(pairKey);
                    }
                }
            }
        }
    }

    /**
     * 初始化关卡之间的路径（预计算）
     */
    public void initPassPath() {
        logger.info("开始初始化关卡路径...");
        for (MapPass startPass : mapPassMap.values()) {
            long startId = startPass.getId();
            // 遍历该关卡所连接的所有疆域
            for (int territoryId : startPass.getCordHashMap().keySet()) {
                Territory territory = territoryMap.get(territoryId);
                if (territory == null) {
                    continue;
                }
                // 获取该疆域连接的其它关卡
                for (List<MapPass> connectedPasses : territory.getNextTerritory().values()) {
                    for (MapPass endPass : connectedPasses) {
                        if (endPass.getId() == startId) {
                            continue; // 跳过自己
                        }
                        if (startPass.getPathHashMap().containsKey(endPass.getId())) {
                            continue; //跳过已经计算的
                        }
                        // 获取起点和终点在这片疆域中的坐标节点
                        Cord startCord = startPass.getCordHashMap().get(territoryId);
                        Cord endCord = endPass.getCordHashMap().get(territoryId);
                        if (startCord == null || endCord == null) {
                            continue;
                        }
                        // 计算路径
                        Future<?> future = ThreadPoolManager.getInstance().addFindPathTask(new ThreadTask("initPassPath") {
                            @Override
                            protected void action() {
                                List<JsonGamePos> path = ThetaStarUtil.findPathBigGirdLazy(startCord.toPos(), endCord.toPos(), GameMap.this);
                                if (path != null && !path.isEmpty()) {
                                    startPass.getPathHashMap().put(endPass.getId(), path);
                                    //双向通行，另一个关卡反向保存路径
                                    List<JsonGamePos> reversed = new ArrayList<>(path);
                                    Collections.reverse(reversed);
                                    endPass.getPathHashMap().put(startId, reversed);
                                } else {
                                    logger.error("GameMap.initPassPath  findPathBigGirdLazy fail");
                                    System.exit(-1);
                                }
                            }
                        });
                        try {
                            // 阻塞当前线程，直到任务完成
                            future.get();
                        } catch (InterruptedException | ExecutionException e) {
                            logger.error("GameMap.initPassPath  future err:{}", ExceptionUtil.show(e));
                            System.exit(-1);
                        }
                    }
                }
            }
        }
        logger.info("关卡路径初始化完成");
    }


    /**
     * 连接两个疆域，并记录所使用的关卡信息
     *
     * @param a       疆域A
     * @param b       疆域B
     * @param mapPass 关卡信息
     */
    private void connectTerritories(Territory a, Territory b, MapPass mapPass) {
        if (a.equals(b)) {
            return;
        }
        a.getNextTerritory().computeIfAbsent(b, k -> new ArrayList<>()).add(mapPass);
        b.getNextTerritory().computeIfAbsent(a, k -> new ArrayList<>()).add(mapPass);
    }

    /**
     * 添加hash阻挡
     *
     * @param x
     * @param y
     */
    public void addBlock(int x, int y) {
        // 获取x行对应的列集合（如果不存在则创建）
        Set<Integer> columns = blocks.computeIfAbsent(x, k -> new HashSet<>());
        // 添加y列到集合中
        columns.add(y);
    }

    /**
     * 移除hash阻挡
     *
     * @param x
     * @param y
     */
    public void removeBlock(int x, int y) {
        if (x >= 0 && x < pointMaxX && y >= 0 && y < pointMaxY) {
            if (blocks.containsKey(x)) {
                Set<Integer> columns = blocks.get(x);
                columns.remove(y);
            }
        }
    }

    /**
     * 检查是否为寻路阻挡
     *
     * @param x
     * @param y
     * @return
     */
    public boolean isBlocked(int x, int y) {
        // 检查x行是否存在，并且y列是否在该行的集合中
        Set<Integer> columns = blocks.get(x);
        return columns != null && columns.contains(y);
    }

    /**
     * 判断指定坐标是否可通过。
     *
     * @param x X坐标
     * @param y Y坐标
     * @return 如果该位置可通过，则返回 true；否则返回 false。
     */
    public boolean isWalkable(int x, int y) {
        if (x < 0 || y < 0 || x >= mapWidth || y >= mapHeight) {
            return false;
        }
        Grid grid = grids[x][y];
        if (grid == null) {
            return false;
        }
        return !grid.isStopBlock();
    }

    /**
     * 检查地图坐标是否不为阻挡
     *
     * @param gamePos
     * @return
     */
    public boolean isNotBlocked(JsonGamePos gamePos) {
        Grid grid = getGirdByPos(gamePos);
        if (grid == null || grid.isStopBlock()) {
            return false;
        }
        if (!grid.isOpenTerritory()) {
            return false;
        }
        Cord cord = gamePosToCord(gamePos);
        if (cord == null || isBlocked(cord.getX(), cord.getY())) {
            return false;
        }
        return true;
    }


    /**
     * 将地图节点坐标转换回游戏内的坐标。
     *
     * @param mapX 地图数组的X索引
     * @param mapY 地图数组的Y索引
     * @return 一个包含游戏内坐标的整数数组，第一个元素是X坐标，第二个元素是Y坐标
     */
    public JsonGamePos mapToGameCoords(int mapX, int mapY) {
        float gameX = (float) mapX / cordPosRatio;
        float gameY = (float) mapY / cordPosRatio;
        return new JsonGamePos(gameX, gameY);
    }

    /**
     * 获取坐标格子
     *
     * @param jsonGamePos 游戏坐标
     * @return 一个包含游戏内坐标的整数数组，第一个元素是X坐标，第二个元素是Y坐标
     */
    public Grid getGirdByPos(JsonGamePos jsonGamePos) {
        float gameX = jsonGamePos.getX();
        float gameY = jsonGamePos.getZ();
        if (gameX < 0 || gameY < 0 || gameX > pointMaxX || gameY > pointMaxY) {
            return null;
        }
        return grids[(int) gameX][(int) gameY];
    }

    /**
     * 获取坐标格子
     *
     * @param mapX 地图数组的X索引
     * @param mapY 地图数组的Y索引
     * @return 一个包含游戏内坐标的整数数组，第一个元素是X坐标，第二个元素是Y坐标
     */
    public Grid getGirdByCoords(int mapX, int mapY) {
        int gameX = (int) (mapX / cordPosRatio);
        int gameY = (int) (mapY / cordPosRatio);
        if (gameX < 0 || gameY < 0 || gameX > pointMaxX || gameY > pointMaxY) {
            return null;
        }
        return grids[gameX][gameY];
    }

    /**
     * 将游戏坐标转换为大格子Node。
     *
     * @return 一个包含地图数组索引的整数数组，第一个元素是X索引，第二个元素是Y索引
     */
    public Node JsonGamePosToMapGirdIndex(JsonGamePos pos) {
        int row = (int) (pos.getX());
        int col = (int) (pos.getZ());
        return getNode(row, col);
    }

    /**
     * 在地图上添加一个圆形阻挡区域。
     *
     * @param centerX 圆形阻挡的中心点X坐标（游戏坐标）
     * @param centerY 圆形阻挡的中心点Y坐标（游戏坐标）
     * @param radius  圆形阻挡的半径
     */
    public void addCircularObstacle(float centerX, float centerY, int radius) {
        // 直接使用游戏坐标作为地图坐标
        int mapCenterX = (int) (centerX * cordPosRatio);
        int mapCenterY = (int) (centerY * cordPosRatio);
        for (int x = mapCenterX - radius; x <= mapCenterX + radius; x++) {
            for (int y = mapCenterY - radius; y <= mapCenterY + radius; y++) {
                // 判断点 (x, y) 是否在圆形区域内，如果是，则设置阻挡
                if (isInsideCircle(mapCenterX, mapCenterY, x, y, radius)) {
                    // 在这里不检查x和y是否大于等于0，因为地图支持负数索引
                    addBlock(x, y);
                }
            }
        }
    }

    /**
     * 从地图上移除一个圆形阻挡区域。
     *
     * @param centerX 圆形阻挡的中心点X坐标（游戏坐标）
     * @param centerY 圆形阻挡的中心点Y坐标（游戏坐标）
     * @param radius  圆形阻挡的半径
     */
    public void removeCircularObstacle(float centerX, float centerY, int radius) {
        // 直接使用游戏坐标作为地图坐标
        int mapCenterX = (int) (centerX * cordPosRatioInt);
        int mapCenterY = (int) (centerY * cordPosRatioInt);
        // 遍历圆形区域内的每个点，清除阻挡
        for (int x = mapCenterX - radius; x <= mapCenterX + radius; x++) {
            for (int y = mapCenterY - radius; y <= mapCenterY + radius; y++) {
                // 判断点 (x, y) 是否在圆形区域内，如果是，则清除阻挡
                if (isInsideCircle(mapCenterX, mapCenterY, x, y, radius)) {
                    removeBlock(x, y);
                }
            }
        }
    }

    /**
     * 判断一个点是否在以 (cx, cy) 为中心，r 为半径的圆内。
     *
     * @param centerX 圆的中心点X坐标
     * @param centerY 圆的中心点Y坐标
     * @param x       要检查的点的X坐标
     * @param y       要检查的点的Y坐标
     * @param radius  圆的半径
     * @return 如果点在圆内，则返回 true；否则返回 false
     */
    private boolean isInsideCircle(int centerX, int centerY, int x, int y, int radius) {
        int dx = x - centerX;
        int dy = y - centerY;
        return (dx * dx + dy * dy) <= (radius * radius);
    }


    /**
     * 检查2个游戏坐标是否是否可以直线相连而不穿过障碍物。
     *
     * @param pos1
     * @param pos2
     * @return
     */
    public boolean canConnectStraight(JsonGamePos pos1, JsonGamePos pos2) {
        return canConnectStraight((int) (pos1.getX() * cordPosRatioInt), (int) (pos1.getZ() * cordPosRatioInt), (int) (pos2.getX() * cordPosRatioInt), (int) (pos2.getZ() * cordPosRatioInt));
    }


    /**
     * 检查两个节点是否可以直线相连而不穿过障碍物。
     *
     * @param x1 起点x
     * @param y1 起点y
     * @param x2 终点x
     * @param y2 终点y
     * @return 如果两点之间可以直线相连并且没有障碍物则返回true，否则返回false
     */
    public boolean canConnectStraight(int x1, int y1, int x2, int y2) {
        int dx = Math.abs(x2 - x1);
        int dy = Math.abs(y2 - y1);
        int sx = (x1 < x2) ? 1 : -1;
        int sy = (y1 < y2) ? 1 : -1;
        int err = dx - dy;
        while (true) {
            if (x1 % 10 != 0 || y1 % 10 != 0) {
                if (isBlocked(x1, y1)) {
                    // 路径上有障碍物
                    return false;
                }
            }
            if (x1 == x2 && y1 == y2) {
                break; // 到达终点
            }
            int e2 = err * 2;
            if (e2 > -dy) {
                err -= dy;
                x1 += sx;
            }
            if (e2 < dx) {
                err += dx;
                y1 += sy;
            }
        }
        // 路径上无障碍物
        return true;
    }


    /**
     * 检查两个节点是否可以直线相连而不穿过障碍物。
     *
     * @param x1 起点x
     * @param y1 起点y
     * @param x2 终点x
     * @param y2 终点y
     * @return 如果两点之间可以直线相连并且没有障碍物则返回true，否则返回false
     */
    public boolean canConnectStraightGrid(int x1, int y1, int x2, int y2) {
        int dx = Math.abs(x2 - x1);
        int dy = Math.abs(y2 - y1);
        int sx = (x1 < x2) ? 1 : -1;
        int sy = (y1 < y2) ? 1 : -1;
        int err = dx - dy;
        while (true) {
            if (grids[x1][y1].isStopBlock()) {
                // 路径上有障碍物
                return false;
            }
            if (x1 == x2 && y1 == y2) {
                break; // 到达终点
            }
            int e2 = err * 2;
            if (e2 > -dy) {
                err -= dy;
                x1 += sx;
            }
            if (e2 < dx) {
                err += dx;
                y1 += sy;
            }
        }
        // 路径上无障碍物
        return true;
    }

    /**
     * 优化路径，通过去除不必要的节点来简化路径。
     *
     * @param path 原始路径
     * @return 优化后的路径
     */
    public List<JsonGamePos> optimizePath(List<Cord> path) {
        if (path == null || path.isEmpty()) {
            return Collections.emptyList(); // 返回空列表
        }
        List<JsonGamePos> optimizedPathPositions = new ArrayList<>();
        if (path.size() >= 3) {
            // 起点总是加入优化路径
            optimizedPathPositions.add(mapToGameCoords(path.get(0).getX(), path.get(0).getY()));
            Cord lastOptimizedNode = path.get(0);
            // 终点总是加入优化路径
            JsonGamePos lastPos = mapToGameCoords(path.get(path.size() - 1).getX(), path.get(path.size() - 1).getY());
            optimizedPathPositions.add(lastPos);
            for (int i = 1; i < path.size() - 1; i++) {
                Cord currentNode = path.get(i);
                Cord nextNode = path.get(i + 1);
                // 检查当前节点是否可以与下一个节点直线相连而不穿过障碍物
                if (!canConnectStraight(lastOptimizedNode, nextNode)) {
                    // 如果不能直线相连，则添加当前节点到优化路径中
                    optimizedPathPositions.add(mapToGameCoords(currentNode.getX(), currentNode.getY()));
                    lastOptimizedNode = currentNode;
                }
            }
        } else {
            // 如果路径长度小于3，则直接转换并返回
            for (Cord cord : path) {
                optimizedPathPositions.add(mapToGameCoords(cord.getX(), cord.getY()));
            }
        }
        return optimizedPathPositions;
    }

    /**
     * 基于坐标的优化路径
     *
     * @param path 输入的路径
     * @return 优化后的路径
     */
    public List<JsonGamePos> optimizeJsonGamePosPath(List<JsonGamePos> path) {
        if (path == null || path.isEmpty()) {
            return Collections.emptyList(); // 返回空列表
        }
        List<JsonGamePos> optimizedPathPositions = new ArrayList<>();
        if (path.size() >= 3) {
            // 起点总是加入优化路径
            optimizedPathPositions.add(path.get(0));
            Cord lastOptimizedCord = gamePosToCord(path.get(0));
            JsonGamePos lastPos = path.get(path.size() - 1); // 获取最后一个位置
            for (int i = 1; i < path.size() - 1; i++) {
                Cord currentCord = gamePosToCord(path.get(i));
                Cord nextCord = gamePosToCord(path.get(i + 1));
                // 检查当前节点是否可以与下一个节点直线相连而不穿过障碍物
                if (!canConnectStraight(lastOptimizedCord, nextCord)) {
                    // 如果不能直线相连，则添加当前节点到优化路径中
                    optimizedPathPositions.add(path.get(i));
                    lastOptimizedCord = currentCord;
                }
            }
            // 终点总是加入优化路径
            optimizedPathPositions.add(lastPos);
        } else {
            // 如果路径长度小于3，则直接返回
            return new ArrayList<>(path);
        }
        return optimizedPathPositions;
    }

    /**
     * 基于坐标的优化路径
     *
     * @param path 输入的路径
     * @return 优化后的路径
     */
    public List<JsonGamePos> optimizeJsonGamePosPathGrid(List<JsonGamePos> path) {
        if (path == null || path.isEmpty()) {
            return Collections.emptyList(); // 返回空列表
        }
        List<JsonGamePos> optimizedPathPositions = new ArrayList<>();
        if (path.size() >= 3) {
            // 起点总是加入优化路径
            optimizedPathPositions.add(path.get(0));
            JsonGamePos checkPos = path.get(0);
            JsonGamePos lastPos = path.get(path.size() - 1); // 获取最后一个位置
            for (int i = 1; i < path.size() - 1; i++) {
                JsonGamePos currentPos = path.get(i);
                JsonGamePos nextPos = path.get(i + 1);
                if (!canConnectStraightGrid((int) checkPos.getX(), (int) checkPos.getZ(), (int) nextPos.getX(), (int) nextPos.getZ())) {
                    // 如果不能直线相连，则添加当前节点到优化路径中
                    optimizedPathPositions.add(path.get(i));
                    checkPos = currentPos;
                }
            }
            // 终点总是加入优化路径
            optimizedPathPositions.add(lastPos);
        } else {
            // 如果路径长度小于3，则直接返回
            return new ArrayList<>(path);
        }
        return optimizedPathPositions;
    }

    /**
     * 地图坐标转为寻路节点
     *
     * @param gamePos
     * @return
     */
    public Cord gamePosToCord(JsonGamePos gamePos) {
        return new Cord((int) (gamePos.getX() * cordPosRatio), (int) (gamePos.getZ() * cordPosRatio));
    }


    /**
     * 判断2个节点是否可以直线相连
     *
     * @param start
     * @param end
     * @return
     */
    public boolean canConnectStraight(Cord start, Cord end) {
        return canConnectStraight(start.getX(), start.getY(), end.getX(), (int) end.getY());
    }


    /**
     * 获取邻居格子
     *
     * @param grid
     * @return
     */
    public List<Grid> getGirdNeighbors(Grid grid) {
        List<Grid> neighbors = new ArrayList<>();
        int row = grid.getRow();
        int col = grid.getCol();
        int territory = grid.getTerritory();
        for (int[] move : moves) {
            int nextRow = row + move[0];
            int nextCol = col + move[1];
            if (nextRow >= 0 && nextRow < mapWidth && nextCol >= 0 && nextCol < mapHeight) {
                Grid currGrid = grids[nextRow][nextCol];
                if (currGrid == null || grid.isStopBlock()) {
                    continue;
                }
                if (territory > 0 && grid.getTerritory() != territory) {
                    continue;
                }
                neighbors.add(currGrid);
            }
        }
        return neighbors;
    }

    /**
     * 获取邻居大格子
     *
     * @param node
     * @param
     * @return
     */
    public List<Node> getGirdNeighbors(Node node, Node endGird) {
        List<Node> neighbors = new ArrayList<>();
        int row = node.getX();
        int col = node.getY();
        int territory = grids[row][col].getTerritory();
        for (int[] move : moves) {
            int nextRow = row + move[0];
            int nextCol = col + move[1];
            if (nextRow >= 0 && nextRow < mapWidth && nextCol >= 0 && nextCol < mapHeight) {
                Grid grid = grids[nextRow][nextCol];
                if (grid == null || grid.isStopBlock()) {
                    continue;
                }
                if (grid.getTerritory() != territory) {
                    continue;
                }
                //寻找到终点大格子
                if (grid.getRow() == endGird.getX() && grid.getCol() == endGird.getY()) {
                    neighbors.add(endGird);
                    continue;
                }
                Node acquire = getNode(nextRow, nextCol);
                neighbors.add(acquire);
            }
        }
        return neighbors;
    }


    /**
     * 找到起点到终点要通过的关卡和疆域
     *
     * @param startPos 起始坐标
     * @param endPos   终点坐标
     * @return 按顺序经过的关卡与对应的下一个疆域ID
     */
    public LinkedHashMap<MapPass, Integer> findPathBetweenTerritories(JsonGamePos startPos, JsonGamePos endPos) {
        Grid startGrid = grids[(int) startPos.getX()][(int) startPos.getZ()];
        int startTerritoryId = startGrid.getTerritory();
        Grid endGrid = grids[(int) endPos.getX()][(int) endPos.getZ()];
        int endTerritoryId = endGrid.getTerritory();
        // 检查起始和结束疆域是否存在
        if (!territoryMap.containsKey(startTerritoryId) || !territoryMap.containsKey(endTerritoryId)) {
            throw new IllegalArgumentException("无效的疆域ID");
        }
        // 如果起点和终点在同一个疆域内，直接返回空列表
        if (startTerritoryId == endTerritoryId) {
            return new LinkedHashMap<>();
        }
        Territory start = territoryMap.get(startTerritoryId);
        Territory end = territoryMap.get(endTerritoryId);
        // 先检查是否可以直接到达（是否有直连的关卡）
        if (start.getNextTerritory().containsKey(end)) {
            List<MapPass> passes = start.getNextTerritory().get(end);
            if (passes != null && !passes.isEmpty()) {
                MapPass nearestPass = getNearestPass(startPos, passes);
                if (nearestPass != null) {
                    LinkedHashMap<MapPass, Integer> result = new LinkedHashMap<>();
                    result.put(nearestPass, endTerritoryId);
                    return result;
                }
            }
        }
        // 否则使用BFS查找路径
        Queue<Territory> queue = new LinkedList<>();
        Map<Territory, Territory> cameFrom = new HashMap<>();     // 记录前一个疆域
        Map<Territory, MapPass> passUsedToEnter = new HashMap<>(); // 到达当前疆域使用的关卡
        Set<Territory> visited = new HashSet<>();
        queue.add(start);
        visited.add(start);
        cameFrom.put(start, null);
        boolean found = false;
        while (!queue.isEmpty()) {
            Territory current = queue.poll();
            for (Map.Entry<Territory, List<MapPass>> entry : current.getNextTerritory().entrySet()) {
                Territory neighbor = entry.getKey();
                List<MapPass> passOptions = entry.getValue();
                if (visited.contains(neighbor)) {
                    continue;
                }
                // 确定从哪个位置出发去比较距离
                JsonGamePos fromPos = startPos;
                if (current != start) {
                    Cord initCord = passUsedToEnter.get(current).getInitCord();
                    fromPos = new JsonGamePos(initCord.getX(), initCord.getY());
                }
                // 在多个关卡中选择距离 fromPos 最近的一个
                MapPass chosenPass = getNearestPass(fromPos, passOptions);
                if (chosenPass == null) {
                    continue; // 无可用关卡，跳过
                }
                visited.add(neighbor);
                cameFrom.put(neighbor, current);
                passUsedToEnter.put(neighbor, chosenPass);
                queue.add(neighbor);
                if (neighbor.getId() == endTerritoryId) {
                    found = true;
                    break;
                }
            }
            if (found) {
                break;
            }
        }
        LinkedHashMap<MapPass, Integer> path = new LinkedHashMap<>();
        if (!found) {
            return path; // 找不到路径则返回空
        }
        Territory step = end;
        while (step != start) {
            MapPass pass = passUsedToEnter.get(step);
            if (pass == null) {
                break;
            }
            int nextTerritoryId = step.getId();
            path.put(pass, nextTerritoryId);
            step = cameFrom.get(step);
        }
        // 因为是从终点往回找，所以反转一下顺序
        List<Map.Entry<MapPass, Integer>> list = new ArrayList<>(path.entrySet());
        Collections.reverse(list);
        LinkedHashMap<MapPass, Integer> reversedPath = new LinkedHashMap<>();
        for (Map.Entry<MapPass, Integer> entry : list) {
            reversedPath.put(entry.getKey(), entry.getValue());
        }
        return reversedPath;
    }

    /**
     * 获取从给定位置出发，最近的关卡
     *
     * @param fromPos  起始坐标
     * @param passList 候选关卡列表
     * @return 最近的关卡
     */
    private MapPass getNearestPass(JsonGamePos fromPos, List<MapPass> passList) {
        if (passList == null || passList.isEmpty()) {
            return null;
        }
        MapPass nearestPass = null;
        double minDistance = Double.MAX_VALUE;
        for (MapPass pass : passList) {
            double distance = MapUtil.getDistance(fromPos, new JsonGamePos(pass.getInitCord().getX(), pass.getInitCord().getY()));
            if (distance < minDistance) {
                minDistance = distance;
                nearestPass = pass;
            }
        }
        return nearestPass;
    }

    /**
     * 获取节点
     *
     * @param nextX
     * @param nextY
     * @return
     */
    public Node getNode(int nextX, int nextY) {
        Node acquire = nodePool.acquire();
        acquire.setX(nextX);
        acquire.setY(nextY);
        return acquire;
    }

    /**
     * 根据id获取关卡
     *
     * @return
     */
    public MapPass getMapPassById(long id) {
        return mapPassMap.get(id);
    }

    /**
     * 检测关卡是否能通行
     *
     * @param allianceId
     * @return
     */
    public boolean checkCanPass(long allianceId, List<Long> passIdList) {
        for (Long passId : passIdList) {
            MapPass mapPass = mapPassMap.get(passId);
            if (mapPass.getAllianceId() == 0 || mapPass.getAllianceId() != allianceId) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取两个对角相邻格子之间，在 cord1 格子内最靠近 cord2 的坐标点（精确到 0.1）
     *
     * @param cord1 第一个格子坐标（作为“起点格子”）
     * @param cord2 第二个格子坐标（目标格子）
     * @return 在 cord1 格子内最接近 cord2 的点
     */
    public JsonGamePos getNearestPoint(Cord cord1, Cord cord2) {
        final double CELL_SIZE = 1.0;
        final double PRECISION = 0.1;
        final double OFFSET = PRECISION; // 最大偏移，避免越界
        final double INNER_MAX = CELL_SIZE - OFFSET; // 如 0.9
        int x1 = cord1.getX();
        int y1 = cord1.getY();
        int x2 = cord2.getX();
        int y2 = cord2.getY();
        // cord1 格子内的四个“候选角点”（精确到 0.1）
        double[][] candidateCorners = {
                {x1 + 0.0, y1 + 0.0},        // 左下
                {x1 + 0.0, y1 + INNER_MAX},  // 左上
                {x1 + INNER_MAX, y1 + 0.0},        // 右下
                {x1 + INNER_MAX, y1 + INNER_MAX}   // 右上
        };
        double minDistSq = Double.MAX_VALUE;
        double[] bestPoint = candidateCorners[0];
        for (double[] point : candidateCorners) {
            double dx = getAxisDistance(point[0], x2, CELL_SIZE);
            double dy = getAxisDistance(point[1], y2, CELL_SIZE);
            double distSq = dx * dx + dy * dy;

            if (distSq < minDistSq) {
                minDistSq = distSq;
                bestPoint = point;
            }
        }
        // 四舍五入到 0.1 精度（虽然 bestPoint 已满足，但确保 float 精度）
        float roundedX = Math.round(bestPoint[0] * 10f) / 10.0f;
        float roundedY = Math.round(bestPoint[1] * 10f) / 10.0f;
        return new JsonGamePos(roundedX, roundedY);
    }

    /**
     * 计算点 value 到目标格 [target, target + size) 的最短轴向距离
     * 如果 value 在格子内，距离为 0
     * 如果在左侧，距离为 target - value
     * 如果在右侧，距离为 value - (target + size)
     */
    private double getAxisDistance(double value, int target, double size) {
        if (value < target) {
            return target - value;
        } else if (value >= target + size) {
            return value - (target + size);
        }
        return 0.0; // 在格子内
    }

}
